/*
 * Copyright (C) 2018 Logos Technology Ltd.
 */

package com.logos.common.source.network;

import com.logos.common.source.network.callback.HttpRespondResultCallBack;
import com.logos.common.source.network.callback.MultiUploadFileProgressListener;
import com.logos.common.source.network.interceptor.CacheInterceptor;
import com.logos.common.source.network.interceptor.DownloadFileInterceptor;
import com.logos.tool.Md5;
import com.logos.tool.RandomString;
import com.logos.tool.log.LogUtil;
import com.logos.tool.string.StringUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * @author Young Ken
 */

public class NetWork {

    public static class Builder {

        String mBaseUrl;
        String mUrl;
        Map<String, File> mFiles;
        Map<String, String> mHeader;
        Map<String, Object> mParam;
        boolean mCache = false;

        /**
         * 整个网络请求全部在子线程中运行，如果访问大量数据需要数据解析成entity，这个时候比较耗时，会让主线程卡顿。
         */
        boolean mRunSubThread = false;
        HttpRespondResultCallBack mCallBack;
        MultiUploadFileProgressListener mMultiUploadFileProgressListener;

        /**
         * base url
         *
         * @param baseUrl base url
         * @return Builder
         */
        public Builder baseUrl(String baseUrl) {
            mBaseUrl = baseUrl;
            return this;
        }

        /**
         * url
         *
         * @param url url
         * @return Builder
         */
        public Builder url(String url) {
            mUrl = url;
            return this;
        }

        /**
         * 请求参数，是键值对的形式
         *
         * @param param 请求参数
         * @return Builder
         */
        public Builder param(Map<String, Object> param) {
            mParam = param;
            return this;
        }

        /**
         * 请求头信息
         *
         * @param header Map
         * @return Builder
         */
        public Builder header(Map<String, String> header) {
            mHeader = header;
            return this;
        }

        /**
         * 上传文件的file
         *
         * @param files Map of File
         * @return Builder
         */
        public Builder files(Map<String, File> files) {
            mFiles = files;
            return this;
        }

        /**
         * 是否开启缓存
         *
         * @param cache base url
         * @return Builder
         */
        public Builder cache(boolean cache) {
            mCache = cache;
            return this;
        }

        /**
         * run sub thread
         *
         * @param subThread thread
         * @return Builder
         */
        public Builder runSubThread(boolean subThread) {
            mRunSubThread = subThread;
            return this;
        }

        /**
         * 回调函数，请求成功和失败
         *
         * @param callBack HttpRespondResultCallBack
         * @return Builder
         */
        public Builder callBack(HttpRespondResultCallBack callBack) {
            mCallBack = callBack;
            return this;
        }

        /**
         * upload file
         *
         * @param listener UploadFileProgressListener
         * @return Builder
         */
        public Builder addMultiUploadFileProgressListener(MultiUploadFileProgressListener
                                                                  listener) {
            mMultiUploadFileProgressListener = listener;
            return this;
        }

        /**
         * 创建NetWork
         *
         * @return NetWork
         */
        public NetWork build() {

            if (StringUtil.isEmpty(mBaseUrl)) {
                throw new IllegalArgumentException("baseUrl is null");
            }

            if (StringUtil.isEmpty(mUrl)) {
                throw new IllegalArgumentException("url is null");
            }

            if (mCallBack == null) {
                throw new IllegalArgumentException("HttpRespondResultCallBack is null");
            }
            return new NetWork();
        }
    }

    /**
     * 创建Builder 方法
     *
     * @return {@linkplain NetWork.Builder}
     */
    public Builder newBuilder() {
        return new Builder();
    }

    /**
     * post 请求
     *
     * @param builder {@linkplain NetWork.Builder}
     */
    public void post(Builder builder) {

        NetWorkClient.Builder netBuilder = getDefaultBuilder(builder);

        NetWorkClient client = netBuilder.build();
        client.post(builder.mUrl, builder.mParam, builder.mCallBack);
    }

    /**
     * get 请求
     *
     * @param builder {@linkplain NetWork.Builder}
     */
    public void get(Builder builder) {

        NetWorkClient.Builder netBuilder = getDefaultBuilder(builder);
        NetWorkClient client = netBuilder.build();

        if (builder.mParam != null) {
            client.get(builder.mUrl, builder.mParam, builder.mRunSubThread, builder.mCallBack);
        } else {
            client.get(builder.mUrl, builder.mRunSubThread, builder.mCallBack);
        }
    }

    /**
     * put 请求
     *
     * @param builder {@linkplain NetWork.Builder}
     */
    public void put(Builder builder) {

        NetWorkClient.Builder netBuilder = getDefaultBuilder(builder);

        NetWorkClient client = netBuilder.build();
        client.put(builder.mUrl, builder.mParam, builder.mCallBack);
    }

    /**
     * delete 请求
     *
     * @param builder {@linkplain NetWork.Builder}
     */
    public void delete(Builder builder) {

        NetWorkClient.Builder netBuilder = getDefaultBuilder(builder);

        NetWorkClient client = netBuilder.build();
        if (builder.mParam != null) {
            client.delete(builder.mUrl, builder.mParam, builder.mCallBack);
        } else {
            client.delete(builder.mUrl, builder.mCallBack);
        }
    }

    /**
     * upload 请求
     *
     * @param builder {@linkplain NetWork.Builder}
     */
    public void upload(Builder builder) {

        NetWorkClient.Builder netBuilder = getDefaultBuilder(builder);

        NetWorkClient client = netBuilder.build();

        if (builder.mFiles == null) {
            throw new IllegalArgumentException("upload method file cannot be null");
        }

        if (builder.mParam != null) {
            client.upload(builder.mUrl, builder.mFiles, builder.mParam,
                    builder.mCallBack, builder.mMultiUploadFileProgressListener);
        } else {
            client.upload(builder.mUrl, builder.mFiles,
                    builder.mCallBack, builder.mMultiUploadFileProgressListener);
        }
    }

    /**
     * upload 请求
     *
     * @param builder {@linkplain NetWork.Builder}
     */
    public void download(Builder builder) {

        NetWorkClient.Builder netBuilder = getDefaultBuilder(builder);
        netBuilder.addDownloadFileFactory(DownloadFileInterceptor.create());
        NetWorkClient client = netBuilder.build();
        client.download(builder.mUrl, builder.mCallBack);
    }

    /**
     * 得到默认的 {@linkplain NetWorkClient.Builder}
     *
     * @param builder {@linkplain NetWork.Builder}
     * @return {@linkplain NetWorkClient.Builder}
     */
    public NetWorkClient.Builder getDefaultBuilder(Builder builder) {
        if (builder == null) {
            throw new IllegalArgumentException("builder is null");
        }

        NetWorkClient.Builder netBuilder = new NetWorkClient.Builder(builder.mBaseUrl);

        if (builder.mHeader != null) {

            netBuilder = netBuilder.addHeader(builder.mHeader);
        }

        if (builder.mCache) {
            netBuilder.addCacheFactory(CacheInterceptor.create());
        }

        return netBuilder;
    }


    public static String formatUrlParam(Map<String, Object> param, boolean isLower) {
        String params = "";
        Map<String, Object> map = param;
        try {
            List<Map.Entry<String, Object>> itmes = new ArrayList<>(map.entrySet());
            //对所有传入的参数按照字段名从小到大排序
            //Collections.sort(items); 默认正序
            //可通过实现Comparator接口的compare方法来完成自定义排序
            Collections.sort(itmes, new Comparator<Map.Entry<String, Object>>() {
                @Override
                public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
                    // TODO Auto-generated method stub
                    return (o1.getKey().toString().compareTo(o2.getKey()));
                }
            });

            //构造URL 键值对的形式
            StringBuffer sb = new StringBuffer();
            for (Map.Entry<String, Object> item : itmes) {
                if (!StringUtil.isEmpty(item.getKey())) {
                    String key = item.getKey();
                    Object value = item.getValue();
                    if (value != null) {
                        String val = String.valueOf(item.getValue());
                        if (!StringUtil.isEmpty(val)) {
                            if (isLower) {
                                sb.append(key.toLowerCase() + "=" + val);
                            } else {
                                sb.append(key + "=" + val);
                            }
                            sb.append("&");
                        }
                    }
                }
            }

            params = sb.toString();
            if (!params.isEmpty()) {
                params = params.substring(0, params.length() - 1);
            }
        } catch (Exception e) {
            return "";
        }
        return params;
    }
}
